package 笔试.面试手撕;


import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author:谢君臣
 * @Date:2021/9/4-21:17
 * @version:1.0
 * @function:
 */
public class 手动实现线程池 {
    public static void main(String[] args) {
        IThreadPool threadPool = new IThreadPool(2);
        for (int i = 0; i < 10; i++) {
            int j = i;
            threadPool.execute(()->{
                System.out.println(j);
            });
        }
    }
}

interface IThread {
    // 提交线程
    void execute(Runnable task);

    // 销毁线程池
    void destroy();
}

class IThreadPool implements IThread {
    private final int Default_Size = 10;
    private boolean running = false;
    private int coreSize;
    private IBlockQueue<Runnable> queue;
    private final HashSet<WorkerThread> workers;

    public IThreadPool() {
        this.coreSize = Default_Size;
        this.queue = new IBlockQueue<>();
        this.queue.setCapacity(Default_Size);
        this.workers = new HashSet<>();
    }

    /**
     *
     * @param coreSize 核心线程数
     */
    public IThreadPool(int coreSize) {
        this.coreSize = coreSize;
        this.queue = new IBlockQueue<>();
        this.queue.setCapacity(Default_Size);
        this.workers = new HashSet<>();
    }

    /**
     *
     * @param coreSize  核心线程数
     * @param listSize 阻塞队列大小
     */
    public IThreadPool(int coreSize, int listSize) {
        this.coreSize = coreSize;
        this.queue = new IBlockQueue<>();
        this.queue.setCapacity(listSize);
        this.workers = new HashSet<>();
    }

    @Override
    public void execute(Runnable task) {
        if (task == null) {
            System.out.println("Task must not null.");
        } else {
            synchronized (this){
                if (workers.size()<coreSize){ //小于核心线程数
                    WorkerThread worker = new WorkerThread(task);
                    worker.start();
                    System.out.println(Thread.currentThread().getName()+ "添加执行");
                    workers.add(worker);
                }else {
                    System.out.println(Thread.currentThread().getName()+ "添加到队列");
                    queue.push(task);
                }
            }
        }
    }

    @Override
    public void destroy() {

    }

    class WorkerThread extends Thread{
        private Runnable task;

        public WorkerThread(Runnable task) {
            this.task = task;
        }

        @Override
        public void run() {
            while (task!=null||(task = queue.poll())!=null){
                try {
                    task.run();
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    task=null;
                }
            }
            synchronized (workers) {
                workers.remove(this);
            }
        }
    }

    class IBlockQueue<T> {
        // 阻塞队列
        private Queue<T> queue = new LinkedList<>();
        // 锁
        private ReentrantLock lock = new ReentrantLock();
        Condition pro = lock.newCondition();
        Condition con = lock.newCondition();
        // 容量
        private int capacity;
        private long timeout;
        // 入队任务
        public void push(T t) {
            lock.lock();
            try {
                while (queue.size() == capacity)   // 队列满
                    pro.await();
                queue.add(t);
                con.signal(); // 唤醒消费
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
        // 出队任务
        public T poll() {
            T poll = null;
            lock.lock();
            try {
                while (queue.isEmpty()) {
                    con.awaitNanos(5);
                }
                poll = queue.poll();
                pro.signal();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            return poll;
        }

        public void setCapacity(int capacity) {
            this.capacity = capacity;
        }
    }
}